import jieba
import re
import random
from datetime import datetime
import matplotlib.pyplot as plt
import numpy as np
from pyecharts.charts import Geo
from pyecharts import options as opts
from pyecharts.globals import GeoType

###====================================================================

# ^_^

###====================================================================


def add_dic():
    """将情绪词典加入jieba自定义词典"""
    jieba.load_userdict('D:/Download/emotion_lexicon/anger.txt')
    jieba.load_userdict('D:/Download/emotion_lexicon/disgust.txt')
    jieba.load_userdict('D:/Download/emotion_lexicon/fear.txt')
    jieba.load_userdict('D:/Download/emotion_lexicon/joy.txt')



def remove_urls(text):
    """删除字符串中的URL"""
    url_pattern = re.compile(r'https?://\S+|www\.\S+')   # 正则表达式
    return url_pattern.sub('', text)   # 去除URL


def clean_word(word_txt):
    """将数据进行处理，去除停用词"""
    loc_total = []
    day_total = []
    words_total = []
    with open('D:/Download/python-week2/my_stopwords.txt', 'r', encoding='utf-8') as file1:
        stopwords = [line.strip() for line in file1.readlines()]
    with open(word_txt, 'r', encoding='utf-8') as fp:
        for line in fp:      # 进行分词
            line = remove_urls(line)   # 去除URL
            loc = line.split('\t')[0]
            sentence = line.split('\t')[1]
            day = datetime.strptime(line.split('\t')[2], "%a %b %d %H:%M:%S +0800 %Y\n")  # 转化为datetime格式
            words_per = jieba.lcut(sentence)
            words_part = []
            for ele in words_per:    # 去除停用词
                if ele not in stopwords:
                    words_part.append(ele)
            words_total.append(words_part)  # 句子的分词列表
            day_total.append(day)  # 时间的汇总列表
            loc_total.append(loc[1:-1])  # 经纬度的汇总列表

    return loc_total, words_total, day_total  # 返回经纬度、句子的分词、时间汇总列表


def judge_emotion(list_emotion):
    """外部函数，调用情感词典生成列表"""
    words_store = []
    emotion_store = []
    list_order = ['anger', 'disgust', 'fear', 'joy', 'sadness']
    for i in range(5):
        with open("D:/Download/emotion_lexicon/new_"+list_order[i]+".txt", 'r', encoding='utf-8') as file_store:
            one_sentence = [line.strip() for line in file_store.readlines()]
        words_store.append(one_sentence)

    def inner_emotion_judge():
        """内部函数"""

        for order in list_emotion:
            emotion_dic = {'anger': 0, 'disgust': 0, 'fear': 0, 'joy': 0, 'sadness': 0}
            for item in order:
                if item in words_store[0]:
                    emotion_dic['anger'] += 1

                elif item in words_store[1]:
                    emotion_dic['disgust'] += 1

                elif item in words_store[2]:
                    emotion_dic['fear'] += 1

                elif item in words_store[3]:
                    emotion_dic['joy'] += 1

                elif item in words_store[4]:
                    emotion_dic['sadness'] += 1

            key_values = sorted(emotion_dic.items(), key=lambda x: x[1], reverse=True)
            if key_values[0][1] == 0:  # 没有出现情绪
                res = 'null'
            elif key_values[1][1] < key_values[0][1]:  # 情绪唯一
                res = key_values[0][0]
            elif key_values[1][1] == key_values[0][1]:   # 不同情绪出现次数一样，随机为某个情绪
                choice = [0, 1]
                for k in range(2, 5):
                    if key_values[k][1] == key_values[0][1]:
                        choice.append(k)
                rand_num = random.randint(0, len(choice)-1)
                res = key_values[choice[rand_num]][0]

            emotion_store.append(res)

        return emotion_store   # 返回情绪列表
    return inner_emotion_judge


def time_relate(emo_kind, time_kind, emo_list, time_list, n):
    """分析情绪的时间变化"""
    if time_kind == 'hour':
        """小时分布"""
        emo_value = [0 for _ in range(24)]  # 24小时的情绪值
        x_axis = [_ for _ in range(24)]  # x轴数值
        for i in range(n):
            if emo_list[i] == emo_kind:
                emo_hour = time_list[i].hour
                emo_value[emo_hour] += 1

        for x, y in zip(x_axis, emo_value):
            plt.text(x, y + 0.3, '%.00f' % y, ha='center', va='bottom', fontsize=7.5)  # 加标签数据

        plt.plot(x_axis, emo_value, 'bo-', alpha=0.5, linewidth=1, label=emo_kind)

        plt.legend()  # 显示上面的label
        plt.xlabel('hour')  # x_label
        plt.ylabel('value')  # y_label
        plt.show()

    elif time_kind == 'week':
        """周数分布"""
        emo_value = [0, 0, 0, 0, 0, 0, 0]  # 7天的情绪值
        x_axis = ['Mon', 'Tue', 'Wen', 'Thu', 'Fri', 'Sat', 'Sun']  # x轴数值
        length = [_ for _ in range(7)]
        for i in range(n):
            if emo_list[i] == emo_kind:
                emo_week = int(time_list[i].isoweekday())
                emo_value[emo_week-1] += 1

        for x, y in zip(length, emo_value):
            plt.text(x, y + 0.3, '%.00f' % y, ha='center', va='bottom', fontsize=7.5)  # 加标签数据

        plt.plot(length, emo_value, 'bo-', alpha=0.5, linewidth=1, label=emo_kind)
        plt.xticks(length, x_axis)
        plt.legend()  # 显示上面的label
        plt.xlabel('week')  # x_label
        plt.ylabel('value')  # y_label
        plt.show()

    elif time_kind == 'month':
        """月份分布"""
        emo_value = [0 for _ in range(12)]  # 12个月的情绪值
        x_axis = [_ for _ in range(1, 13)]  # x轴
        for i in range(n):
            if emo_list[i] == emo_kind:
                emo_month = time_list[i].month
                emo_value[emo_month-1] += 1

        for x, y in zip(x_axis, emo_value):
            plt.text(x, y + 0.3, '%.00f' % y, ha='center', va='bottom', fontsize=7.5)  # 加标签数据

        plt.plot(x_axis, emo_value, 'bo-', alpha=0.5, linewidth=1, label=emo_kind)

        plt.legend()  # 显示上面的label
        plt.xlabel('month')  # x_label
        plt.ylabel('value')  # y_label
        plt.show()


def region_list():
    """北京地区的边界坐标"""
    list_region = []
    ans = ''
    flag = 0
    list_dot = []
    with open("D:/Download/python-week3/北京市.txt", 'r', encoding='utf-8') as fp:
        for num in fp.read():
            if num not in ['[', ']', ',']:
                ans += num
            elif num == '[':
                flag += 1
            elif num == ',' and flag == 1:
                list_dot.append(float(ans))
                flag += 1
                ans = ''
            elif num == ']' and flag == 2:
                list_dot.append(float(ans))
                list_dot.reverse()
                list_region.append(list_dot)
                list_dot = []
                flag = 0
                ans = ''
    return list_region


def in_region(list_region, lat, lon):
    """
    接受参数为北京边界地区的纬度、经度列表，带判断的纬度和经度，判断其是否在这一区域
    采用射线法进行判断
    """
    count = 0
    lat = float(lat)
    lon = float(lon)
    for i in range(len(list_region)):
        # 如果是最后一个元素，那么必然是和第一个一样的，就啥也不干
        if i + 1 == len(list_region):
            break
        # 如果不是最后一个元素，那么需要和后一个元素一起判断给定点是否在区域内
        la_1 = list_region[i][0]
        lo_1 = list_region[i][1]

        la_2 = list_region[i + 1][0]
        lo_2 = list_region[i+1][1]

        # 以纬度确定位置，沿纬度向右作射线，看交点个数
        if lat < min(la_1, la_2):
            continue
        if lat > max(la_1, la_2):
            continue
        # 如果和某一个共点那么直接返回true
        if (lat, lon) == (la_1, lo_1) or (lat, lon) == (la_2, lo_2):
            return 1
        # 如果和两点共线
        if lat == la_1 == la_2:
            if lon < min(lo_1, lo_2) or lon > max(lo_1, lo_2):
                return 0
            else:
                return 1
        # 接下来只需考虑射线穿越的情况，该情况下的特殊情况是射线穿越顶点
        # 求交点的精度
        cross_lon = (lat - la_1) * (lo_2 - lo_1) / (la_2 - la_1) + lo_1
        # 因为需要考虑特殊情况的射线穿越顶点，因此只判断是不是穿越左边这个顶点
        if cross_lon == la_1:
            count += 1
        # 其他情况
        elif cross_lon > lon:
            count += 1

    if count % 2 == 0:
        return 0
    return 1

import inspect
class BaseClass:#添加baseclass
	num_base_calls=0
	def call_me(self):
		print("calling method on Base Class")
		BaseClass.num_base_calls+=1

def location_relate(loc_total, emotion_list, radius, n):
    """中心点周围半径内的情绪分布饼图"""
    center_loc = [39.904989, 116.405285]  # 北京中心的经纬度坐标
    emo_dic = {'anger': 0, 'disgust': 0, 'fear': 0, 'joy': 0, 'sadness': 0}
    for i in range(n):
        latitude = float(loc_total[i].split(',')[0].strip())   # 纬度
        longitude = float(loc_total[i].split(',')[1].strip())   # 经度
        if ((latitude - center_loc[0])**2 + (longitude - center_loc[1])**2) <= radius**2 and emotion_list[i] != 'null':
            emo_dic[emotion_list[i]] += 1
    location_value = list(emo_dic.values())
    emo_label = list(emo_dic.keys())
    plt.pie(location_value, labels=emo_label,
            colors=["#d5695d", "#5d8ca8", "#65a479", "#a564c9", '#515792'], autopct='%3.2f%%')
    plt.legend()
    plt.title('中心分布图')
    plt.rcParams['font.sans-serif'] = ['Katti', 'SimHei']
    plt.show()

def location_relate(loc_total, emotion_list, radius, n):
    """中心点周围半径内的情绪分布饼图"""
    center_loc = [39.904989, 116.405285]  # 北京中心的经纬度坐标
    emo_dic = {'anger': 0, 'disgust': 0, 'fear': 0, 'joy': 0, 'sadness': 0}
    for i in range(n):
        latitude = float(loc_total[i].split(',')[0].strip())   # 纬度
        longitude = float(loc_total[i].split(',')[1].strip())   # 经度
        if ((latitude - center_loc[0])**2 + (longitude - center_loc[1])**2) <= radius**2 and emotion_list[i] != 'null':
            emo_dic[emotion_list[i]] += 1
    location_value = list(emo_dic.values())
    emo_label = list(emo_dic.keys())
    plt.pie(location_value, labels=emo_label,
            colors=["#d5695d", "#5d8ca8", "#65a479", "#a564c9", '#515792'], autopct='%3.2f%%')
    plt.legend()
    plt.title('中心分布图')
    plt.rcParams['font.sans-serif'] = ['Katti', 'SimHei']
    plt.show()


def show_geo(region, emotion, location):
    """在北京地图对情绪的空间分布进行可视化"""
    emo = {'sadness': 5, 'joy': 15, 'fear': 25, 'disgust': 35, 'anger': 45}
    g = Geo()

    data_pair = []

    g.add_schema(maptype='北京')

    for k in range(len(emotion)):
        a = float(location[k].split(',')[0].strip())
        b = float(location[k].split(',')[1].strip())
        if in_region(region, a, b) == 1:
            if emotion[k] != 'null':
                data_pair.append((emotion[k] + str(k), emo[emotion[k]]))
                g.add_coordinate(emotion[k] + str(k), b, a)
            # 定义坐标对应的名称，添加到坐标库中 add_coordinate(name, lng, lat)
    # 将数据添加到地图上
    g.add('', data_pair, type_=GeoType.EFFECT_SCATTER, symbol_size=5)
    # 设置样式
    g.set_series_opts(label_opts=opts.LabelOpts(is_show=False))
    # 自定义分段 color 可以用取色器取色

    pieces = [
        {'min': 1, 'max': 10, 'label': 'sadness', 'color': '#8D7513'},
        {'min': 10, 'max': 20, 'label': 'joy', 'color': '#515792'},
        {'min': 20, 'max': 30, 'label': 'fear', 'color': '#B5332E'},
        {'min': 30, 'max': 40, 'label': 'disgust', 'color': '#5A7C4D'},
        {'min': 40, 'max': 50, 'label': 'anger', 'color': '#FDB638'}
    ]
    # 灰、紫、红、绿、黄

    g.set_global_opts(
        visualmap_opts=opts.VisualMapOpts(is_piecewise=True, pieces=pieces),
        title_opts=opts.TitleOpts(title="北京市-情绪分布地图"),
    )
    return g


def main():
    add_dic()
    loc_total, words_total, day_total = clean_word('D:/Download/python-week2/weibo.txt')  # 经纬度、分词、时间
    func = judge_emotion(words_total)  # 闭包函数，加载情感词典
    emotion_list = func()  # 每个句子的情绪列表
    emo_kind = input('输入情绪的种类(anger/disgust/fear/joy/sadness):')
    time_kind = input('输入情绪的分析时间(hour/week/month):')
    radius = float(input('请输入半径:'))
    n = len(emotion_list)
    time_relate(emo_kind, time_kind, emotion_list, day_total, n)
    # location_relate(loc_total, emotion_list, radius, n)
    # region_beijing = region_list()
    # g = show_geo(region_beijing, emotion_list, loc_total)
    # # 渲染成html, 可用浏览器直接打开
    # g.render('beijing_emotion.html')


if __name__ == '__main__':
    main()
